const SHA256 = require('/usr/local/lib/node_modules/crypto-js/sha256');

class Message{
	constructor(from,to,amount){
		this.from = from;
		this.to = to;
		this.amount = amount;

	}
}
class Block {
	calHash() {
		return SHA256(this.prevhash + this.ts + JSON.stringify(this.data)+this.nonce).toString();
	}
	constructor( ts, data, prevhash = '') {		
		this.ts = ts;
		this.data = data;
		this.prevhash = prevhash;
		this.hash = this.calHash();
		this.nonce = 0;
	}
	mineBlock(difficulty){

		while(this.hash.substring(0,difficulty) !== Array(difficulty+1).join('0')){
			this.nonce++;
			this.hash = this.calHash();
		}
		console.log("new block mined:"+this.hash);
	}
}

class Blockchain {
	constructor() {
		this.chain = [this.createGensisBlock()];
		this.difficulty = 3;
		this.pendingData = [];
		this.miningReward = 100;
	}	

	createGensisBlock(){
		return new Block("01/01/2018","gensis block","0");
	}
	getLatestBlock(){
		return this.chain[this.chain.length - 1];
	}
	minePendingData(addr){

		let block = new Block(Date.now(),this.pendingData);
		block.mineBlock(this.difficulty);
		console.log("successfully mined a new block");
		this.chain.push(block);
		this.pendingData=[
			new Message(null,addr,this.miningReward)
		];
	}
	isChainValid(){
		for(let i=1;i<this.chain.length;i++){
			const currentBlock = this.chain[i];
			const prevBlock = this.chain[i-1];
			if(currentBlock.prevhash != prevBlock.hash){
				return false;
			}
			if(currentBlock.hash != currentBlock.calHash()){
				return false;
			}
		}
		return true;
	}
	createMessage(msg){
		this.pendingData.push(msg);
	}
	getBalanceOfAddr(addr){
		let balance = 0;
		for(let i=0;i<this.chain.length;i++){
			
			for(let j=0;j<this.chain[i].data.length;j++){
				if(this.chain[i].data[j].from == addr){
					balance -= this.chain[i].data[j].amount;
				}
				if(this.chain[i].data[j].to == addr){
					balance += this.chain[i].data[j].amount;
				}
			}
		}
		return balance;
	}
}

let scottCoin = new Blockchain();
scottCoin.createMessage(new Message("addr1","addr2",300));
scottCoin.createMessage(new Message("addr2","addr1",50));
// scottCoin.addBlock(new Block("02/02/2018",{amount:4}));
// scottCoin.addBlock(new Block("03/03/2018",{amount:5}));

scottCoin.minePendingData("addr3");

// console.log(JSON.stringify(scottCoin,null,4));
console.log(scottCoin.getBalanceOfAddr("addr2"));
scottCoin.minePendingData("addr3");
// console.log(JSON.stringify(scottCoin,null,4));
console.log(scottCoin.getBalanceOfAddr("addr3"));

// scottCoin.chain[1].data={amount:10};
// scottCoin.chain[1].hash = scottCoin.chain[1].calHash();
// console.log(scottCoin.isChainValid());

